﻿

namespace Tentacle.Downloader
{
    using System;
    //
    using System.Collections;
    using System.Collections.Generic;
    using System.Net;
    //
    using Tentacle.Core;
    //
    using static Utils.Hepler;
    //

    public sealed class RemoteNodeManager : IEnumerable<IDownloader>
    {
        RemoteDiscorveryService     _service;
        List<IDownloader>           _nodeList;
        HashSet<string>             _endPointSet;

        public RemoteNodeManager()
        {
            _endPointSet = new HashSet<string>();
            _service = new RemoteDiscorveryService();
            _nodeList = new List<IDownloader>();

            _service.Discovery += OnDiscovery;
        }

        #region IEnumerable<RemoteNode> Interface 

        public IEnumerator<IDownloader> GetEnumerator()
        {
            return ((IEnumerable<IDownloader>)this._nodeList).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<IDownloader>)this._nodeList).GetEnumerator();
        }

        #endregion

        private void OnDiscovery(IPEndPoint ip)
        {
            if (_endPointSet.Add(ip.ToString())) {
                lock (_nodeList) {
                    var node = new RemoteNode(ip);
                    Trace(node.ToString());
                    node.Disconnected += OnDisconnected;
                    node.DownloadFailed += OnDownloadFailed;
                    node.DownloadCompleted += OnDownloadCompleted;
                    _nodeList.Add(node);
                }
            }
        }

        private void OnDisconnected(RemoteNode thisNode)
        {
            Console.WriteLine(thisNode);
            thisNode.DownloadCompleted -= OnDownloadCompleted;
            thisNode.DownloadFailed -= OnDownloadFailed;
            Trace(thisNode.Guid);
            _endPointSet.Remove(thisNode.LocalEndPoint.ToString());
            _nodeList.Remove(thisNode);
        }

        void OnDownloadCompleted(WebPage page)
        {
            DownloadCompleted?.Invoke(page);
        }

        void OnDownloadFailed(string errorMessage)
        {
            DownloadFailed?.Invoke(errorMessage);
        }

        public void Remove(RemoteNode node)
        {
            node.DownloadCompleted -= OnDownloadCompleted;
            node.DownloadFailed -= OnDownloadFailed;
            _endPointSet.Remove(node.LocalEndPoint.ToString());
            _nodeList.Remove(node);
        }

        public event DownloadCompletedHandler DownloadCompleted;

        public event DownloadFailedHandler DownloadFailed;
    }
}
